﻿using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.Service.Cache;
using Pay.TO;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Pay.Service.Service {
    public class RedRecordService : ServiceBase, IRedRecordService, IDisposable {
        private IUnitOfWork _iUnitOfWork;
        private ISettingService _settingService;
        private IMerchantService _iMerchantService;
        private IPlayingService _iPlayingService;
        private readonly static object _getRedAndHorsePowerLock = new object();
        public RedRecordService(IUnitOfWork iUnitOfWork, IMerchantService iMerchantService, ISettingService settingService, IPayHtmlService iPayHtmlService, IPlayingService iPlayingService)
            : base(iUnitOfWork) {
            this._iUnitOfWork = iUnitOfWork;
            this._iMerchantService = iMerchantService;
            this._settingService = settingService;
            this._iPlayingService = iPlayingService;
        }
        /// <summary>
        /// 生产红钻
        /// </summary>
        /// <param name="id">用户id</param>
        public void ProductRed(long id) {
            try {
                var member = _iMerchantService.GetTokenUser(id);
                if (!member.is_verify_no_card) {//实名认证未通过
                    return;
                }
                RedRecord record = context.RedRecord.FirstOrDefault(s => s.MerchantId == id);
                //三天未登录时，一登录就减马力
                var taskDayLogin = context.TokenTaskDayLogin.Where(o => o.UserId == id).FirstOrDefault();
                if (taskDayLogin != null) {
                    DateTime lastLoginTime = taskDayLogin.LoginTime==0? taskDayLogin.Time.ToDateTime().Date: taskDayLogin.LoginTime.ToDateTime().Date;
                    int timeDay = (DateTime.Now - lastLoginTime.Date.AddDays(1)).Days;
                    if (timeDay >= 3 && record.TotalHorsePower > 30) {
                        int power = record.TotalHorsePower - 30;
                        for (int i = 0, j = timeDay - 2; i < j; i++) {
                            int value = 0;
                            if (power <= 0) break;
                            if (power < 3) value = power; else value = 3;
                            power = power - value;
                            UserSoupValueHis userSoupValue = new UserSoupValueHis() { UserId = id, TaskType = ETaskType.NoLogin, ItemId = 0, CreateTime = lastLoginTime.AddDays((i + 3)).ToUnix(), SoupValue = value };
                            context.UserSoupValueHis.Add(userSoupValue);
                            record.TotalHorsePower = record.TotalHorsePower - value;
                        }
                    }
                    if (taskDayLogin.LoginTime != DateTime.Now.Date.ToUnixInt()) { taskDayLogin.LoginTime = DateTime.Now.Date.ToUnixInt(); }
                }

                DateTime dt = DateTime.Now;
                Dictionary<DateTime, List<decimal>> dic = record.DayRedDrill.ToObject<Dictionary<DateTime, List<decimal>>>();
                long startime = dt.Date.ToUnix();
                long endtime = dt.Date.AddDays(1).ToUnix();
                //减于临时马力
                decimal daysum = 0;
                var soupSnaps = context.UserSoupValueSnap.Where(c => c.MerchantId == id && c.EffectiveTime < startime).ToList();
                if (soupSnaps.Count > 0) {
                    var soupSnap = soupSnaps.Sum(c => (int?)c.SoupValue);
                    record.TotalHorsePower -= soupSnap.Value;
                    context.UserSoupValueSnap.RemoveRange(soupSnaps);
                }

                decimal rednum = 0;
                var token = _settingService.GetTokenSetting().token;
                int dayTotalRed = token.day_total_red_drill;
                int merchantTotalHorsePower = token.total_horse_power;
                var memberRedDetails = context.RedProductRecordDetail.Where(s => s.MerchantId == id).ToList() ?? new List<RedProductRecordDetail>();
                //未产钻
                if (record.DayRedDrill == "{}") {
                    decimal redNum = (decimal)dayTotalRed * record.TotalHorsePower / merchantTotalHorsePower;
                    //红钻开始生成时间
                    DateTime rndTime = record.NextProductionTime.ToDateTime();
                    int day = (int)(dt - rndTime).TotalDays;
                    day = day == 0 ? 1 : day;
                    DateTime nextTime = rndTime.AddDays(day);
                    dic = RedMakeHelp.GetTimeAndRed(nextTime, redNum);
                    string dayRedDrill = dic.ToJson();
                    record.DayRedDrill = dayRedDrill;
                    record.NextProductionTime = nextTime.ToUnix();
                    //_iUnitOfWork.Commit("RedRecord" + id);
                }
                //第一登录
                if (record.RegisterTime == record.NextProductionTime) {
                    foreach (var d in dic) {
                        long dtime = d.Key.ToUnix();
                        bool ishas = memberRedDetails.Where(s => s.RedProductionTime == dtime).Count() > 0;
                        if (d.Key < dt && ishas == false) {
                            var redList = dic[d.Key];
                            List<RedProductRecordDetail> list = new List<RedProductRecordDetail>();
                            foreach (var red in redList) {
                                rednum += red;
                                if (daysum + rednum > dayTotalRed) break;
                                RedProductRecordDetail detail = new RedProductRecordDetail();
                                detail.MerchantId = id;
                                detail.HorsePower = 0;
                                detail.RedDrill = red;
                                detail.Type = 2;
                                detail.IsReceive = false;
                                detail.CreateTime = DateTime.Now.ToUnix();
                                detail.RedProductionTime = d.Key.ToUnix();
                                detail.RedRecordId = record.Id;
                                list.Add(detail);
                            }
                            if (list.Count > 0) {
                                context.RedProductRecordDetail.AddRange(list);
                                //_iUnitOfWork.Commit("RedRecord" + id);
                            }

                        }
                    }
                }
                //生成注册后下一次发放时间和红钻
                if (dt > dic.Select(s => s.Key).LastOrDefault() && record.IsFinish == false) {
                    decimal redNum = (decimal)dayTotalRed * record.TotalHorsePower / merchantTotalHorsePower;
                    //红钻开始生成时间
                    DateTime rndTime = record.RegisterTime.ToDateTime().AddDays(1);
                    string dayRedDrill = RedMakeHelp.GetTimeAndRed(rndTime, redNum).ToJson();
                    record.DayRedDrill = dayRedDrill;
                    record.NextProductionTime = rndTime.ToUnix();
                    record.IsFinish = true;
                    //_iUnitOfWork.Commit("RedRecord" + id);
                }

                bool flag = false;
                //注册后的第二天以后
                if (dt > record.RegisterTime.ToDateTime().AddDays(1) && record.NextProductionTime.ToDateTime() <= dt) {
                    //用户未领取的红钻
                    int count = memberRedDetails.Count;
                    foreach (var d in dic) {
                        if (flag) break;
                        var dtime = d.Key.ToUnix();
                        if (count >= 25) break;
                        bool ishas = memberRedDetails.Where(s => s.RedProductionTime == dtime).Count() > 0;
                        if (d.Key < dt && !ishas) {
                            var redList = dic[d.Key];
                            List<RedProductRecordDetail> list = new List<RedProductRecordDetail>();
                            foreach (var red in redList) {
                                if (count > 30) break;
                                rednum += red;
                                if (daysum + rednum > dayTotalRed) { flag = true; break; }
                                RedProductRecordDetail detail = new RedProductRecordDetail();
                                detail.MerchantId = id;
                                detail.HorsePower = 0;
                                detail.RedDrill = red;
                                detail.Type = 2;
                                detail.IsReceive = false;
                                detail.CreateTime = DateTime.Now.ToUnix();
                                detail.RedProductionTime = d.Key.ToUnix();
                                detail.RedRecordId = record.Id;
                                list.Add(detail);
                                count += 1;
                            }
                            if (list.Count > 0) {
                                context.RedProductRecordDetail.AddRange(list);
                                //_iUnitOfWork.Commit("RedRecord" + id);
                            }
                        }
                    }
                }
                //当天红钻发完了
                if (flag) {
                    decimal redNum = (decimal)dayTotalRed * record.TotalHorsePower / merchantTotalHorsePower;
                    //红钻开始生成时间
                    DateTime rndTime = DateTime.Now.Date.AddDays(1);
                    string dayRedDrill = RedMakeHelp.GetTimeAndRed(rndTime, redNum).ToJson();
                    record.DayRedDrill = dayRedDrill;
                    record.NextProductionTime = rndTime.ToUnix();
                    //_iUnitOfWork.Commit("RedRecord" + id);
                }
                _iUnitOfWork.Commit("RedRecord" + id);
            } catch (Exception ex) {
                var log = IocHelper.Get<ILogHelper>("info");
                log.Error(ex.Message, ex);
            }
        }

        /// <summary>
        /// 获取钻石
        /// </summary>
        /// <param name="id">红钻记录id</param>
        /// <param name="merchantId">用户id</param>
        /// <returns></returns>
        public bool ReciveRed(long id, long merchantId) {
            var member = _iMerchantService.GetTokenUser(merchantId);
            if (member.disabled) {
                throw new ServerErrorException("账号已被禁用，不能进行领钻");
            }
            if (!member.is_verify_no_card) {//实名认证未通过
                throw new ServerErrorException("实名认证未通过，请等待实名认证通过再进行领钻操作");
            }
            var details = context.RedProductRecordDetail.Where(s => s.MerchantId == merchantId).ToList();
            RedProductRecordDetail redRecordDetail = details.Where(s => s.Id == id).FirstOrDefault();
            if (redRecordDetail == null) throw new ServerErrorException("领取失败,请刷新页面");
            if (redRecordDetail.IsReceive) return true;
            RedRecord record = context.RedRecord.FirstOrDefault(s => s.MerchantId == merchantId);
            var token = _settingService.GetTokenSetting().token;
            int dayTotalRed = token.day_total_red_drill;
            int merchantTotalHorsePower = token.total_horse_power;
            DateTime dt = DateTime.Now;
            //用户每日获得红钻数
            decimal redNum = (decimal)dayTotalRed * record.TotalHorsePower / merchantTotalHorsePower;
            //红钻开始生成时间
            DateTime rndTime = dt;
            string DayRedDrill = string.Empty;
            Dictionary<DateTime, List<decimal>> dic = record.DayRedDrill.ToObject<Dictionary<DateTime, List<decimal>>>();
            //注册第一天 
            if (record.RegisterTime.ToDateTime() < dt && record.RegisterTime.ToDateTime().AddDays(1) > dt) {
                record.TotalRedDrill = record.TotalRedDrill + redRecordDetail.RedDrill;
                if (details.Where(s => s.RedProductionTime == redRecordDetail.RedProductionTime).Count() == 1) {
                    var item = dic.Where(s => s.Key.ToUnix() == redRecordDetail.RedProductionTime).FirstOrDefault();
                    dic.Remove(item.Key);
                    record.DayRedDrill = dic.ToJson();
                }

            } else {
                int detailsCount = details.Count();
                if (details.Where(s => s.RedProductionTime == redRecordDetail.RedProductionTime).Count() == 1) {
                    var item = dic.Where(s => s.Key.ToUnix() == redRecordDetail.RedProductionTime).FirstOrDefault();
                    dic.Remove(item.Key);
                    record.DayRedDrill = dic.ToJson();
                }
                if (detailsCount == 1) {
                    DayRedDrill = RedMakeHelp.GetTimeAndRed(rndTime, redNum).ToJson();
                    record.DayRedDrill = DayRedDrill;
                    record.NextProductionTime = rndTime.ToUnix();
                    record.TotalRedDrill = record.TotalRedDrill + redRecordDetail.RedDrill;
                } else {
                    record.TotalRedDrill = record.TotalRedDrill + redRecordDetail.RedDrill;
                }
            }

            var redDetail = new RedRecordDetail() {
                MerchantId = redRecordDetail.MerchantId,
                IsReceive = true,
                CreateTime = redRecordDetail.CreateTime,
                RedDrill = redRecordDetail.RedDrill,
                ReceiveTime = dt.ToUnix(),
                HorsePower = redRecordDetail.HorsePower,
                RedProductionTime = redRecordDetail.RedProductionTime,
                RedRecordId = redRecordDetail.RedRecordId,
                Remark = redRecordDetail.Remark,
                Type = redRecordDetail.Type
            };
            context.RedRecordDetail.Add(redDetail);
            context.RedProductRecordDetail.Remove(redRecordDetail);
            int result = 0;
            var tags = new List<string> { "RedRecord" + merchantId };
            try {
                result = _iUnitOfWork.Commit(tags.ToArray());
            } catch (Exception ex) {
                var log = IocHelper.Get<ILogHelper>("data_error");
                log.Error(ex.Message, ex);
            }
            return result > 0;
        }

        /// <summary>
        /// 获取未领取的钻石
        /// </summary>
        /// <param name="id">用户id</param>
        /// <returns></returns>
        public List<redrecorddetail_dto> GetRedRecordDetails(long id) {
            var list = context.RedProductRecordDetail.Where(s => s.MerchantId == id).FromCache<RedProductRecordDetail, redrecorddetail_dto>("RedRecord" + id);
            return list;
        }

        /// <summary>
        /// 红钻 和马力总排行
        /// </summary>
        /// <returns></returns>
        public List<red_rank_dto> GetRedAndHorsePower() {
            DateTime time = DateTime.Now;
            var key = string.Format("RedSort{0}_{1}_{2}_{3}", time.Year, time.Month, time.Day, time.Hour);
            var obj = _iUnitOfWork.GetCache<List<red_rank_dto>>(key);
            if (obj != null) return obj;
            return new List<red_rank_dto>();

            //List<red_rank_dto> list = new List<red_rank_dto>();
            ////var testMobileIds = context.Merchants.Where(s => s.Mobile.Contains(t_RequestMethod.TestMobiePrefix) || s.Disabled == true).Select(s => s.Id).ToList();//排除测试和禁用用户
            //var redRecords = context.RedRecord.Where(s => !s.Merchant.Disabled && !s.Merchant.IsPlatform);
            //var redData = redRecords.OrderByDescending(o => o.TotalRedDrill).ThenBy(o => o.CreateTime).Take(20).ToArray().Select((x, i) => new red_dto { id = i + 1, red_drill = x.TotalRedDrill, nick_name = x.Merchant == null ? "" : x.Merchant.Name }).ToList();
            //list.Add(new red_rank_dto { type = 1, list = redData, datetime = time.ToString("yyyy-MM-dd HH") });

            ////马力排行
            //var horseData = redRecords.OrderByDescending(o => o.TotalHorsePower).ThenBy(o => o.CreateTime).Take(20).ToArray().Select((x, i) => new red_dto { id = i + 1, horse_power = x.TotalHorsePower, nick_name = x.Merchant == null ? "" : x.Merchant.Name }).ToList();
            //list.Add(new red_rank_dto { type = 2, list = horseData, datetime = time.ToString("yyyy-MM-dd HH") });

            //_iUnitOfWork.SetCache(key, list, 3600);
            //return list;
        }

        /// <summary>
        /// 定时--马力 红钻排行到缓存
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public bool GetRedAndHorsePower2() {
            DateTime time = DateTime.Now;
            var key = string.Format("RedSort{0}_{1}_{2}_{3}", time.Year, time.Month, time.Day, time.Hour);
            var obj = _iUnitOfWork.GetCache<List<red_rank_dto>>(key);
            if (obj != null) return true;

            List<red_rank_dto> list = new List<red_rank_dto>();
            //var testMobileIds = context.Merchants.Where(s => s.Mobile.Contains(t_RequestMethod.TestMobiePrefix) || s.Disabled == true).Select(s => s.Id).ToList();//排除测试和禁用用户
            var redRecords = context.RedRecord.Where(s => !s.Merchant.Disabled && !s.Merchant.IsPlatform);
            var redData = redRecords.OrderByDescending(o => o.TotalRedDrill).ThenBy(o => o.CreateTime).Take(20).ToArray().Select((x, i) => new red_dto { id = i + 1, red_drill = x.TotalRedDrill, nick_name = x.Merchant == null ? "" : x.Merchant.Name }).ToList();
            list.Add(new red_rank_dto { type = 1, list = redData, datetime = time.ToString("yyyy-MM-dd HH") });

            //马力排行
            var horseData = redRecords.OrderByDescending(o => o.TotalHorsePower).ThenBy(o => o.CreateTime).Take(20).ToArray().Select((x, i) => new red_dto { id = i + 1, horse_power = x.TotalHorsePower, nick_name = x.Merchant == null ? "" : x.Merchant.Name }).ToList();
            list.Add(new red_rank_dto { type = 2, list = horseData, datetime = time.ToString("yyyy-MM-dd HH") });

            _iUnitOfWork.SetCache(key, list, 3600);
            return true;
        }

        /// <summary>
        /// 获取用户红钻马力排行
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public user_red_dto GetUserRed(long id) {
            var obj = _iUnitOfWork.GetCache<user_red_dto>("RedSort" + id);
            if (obj != null) return obj;
            user_red_dto userRed = new user_red_dto();
            var red = context.RedRecord.FirstOrDefault(s => s.MerchantId == id);
            if (red != null) {
                List<SqlParameter> paramArray = new List<SqlParameter>();
                paramArray.Add(new SqlParameter("@user_id", id));
                var sortRedPower = context.Database.SqlQuery<SortRedPower>(@"select 
                      TotalRedDrill,TotalHorsePower,MerchantId from( 
                      select ROW_NUMBER() OVER (ORDER BY a.TotalRedDrill desc) AS TotalRedDrill,  
                      ROW_NUMBER() OVER (ORDER BY a.TotalHorsePower desc) AS TotalHorsePower,MerchantId 
                      from mc_RedRecord as a 
                  ) as a  where MerchantId=@user_id", paramArray.ToArray()).FirstOrDefault();
                userRed.r_no = sortRedPower.TotalRedDrill;
                userRed.red_drill = red.TotalRedDrill - red.ConsumeRedDrill;
                userRed.total_red_drill = red.TotalRedDrill;
                userRed.h_no = sortRedPower.TotalHorsePower;
                userRed.horse_power = red.TotalHorsePower;
                _iUnitOfWork.SetCache("RedSort" + id, userRed, 3600);
            }
            return userRed;
        }

        /// <summary>
        /// 用户获取的红钻记录或马力记录列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<user_record_dto> GetUserRedRecords(RedQuery query) {
            if (query.type == 1) {
                var result = string.Format("RedRecord{0}_{1}_{2}", query.merchant_id, query.page, query.size)
                    .FromCacheLinq(() => {
                        List<SqlParameter> paramArray = new List<SqlParameter>();
                        paramArray.Add(new SqlParameter("@user_id", query.merchant_id));
                        paramArray.Add(new SqlParameter("@page", query.page));
                        paramArray.Add(new SqlParameter("@size", query.size));
                        SqlParameter param = new SqlParameter("@total_result", SqlDbType.Int);
                        param.Direction = ParameterDirection.Output;
                        paramArray.Add(param);
                        var rows = context.Database.SqlQuery<user_record_dto>("EXEC [sp_red_detail] @user_id,@page,@size,@total_result out", paramArray.ToArray()).ToList();
                        int total_result = (int)paramArray[3].Value;
                        var list = new PagedResult<user_record_dto>(rows, total_result, query.page, query.size);
                        return list;
                    }, "RedRecord" + query.merchant_id);
                return result;
            } else {
                Expression<Func<UserSoupValueHis, bool>> filter = c => c.UserId == query.merchant_id;
                var list = context.UserSoupValueHis.FromCachePaged<UserSoupValueHis, user_record_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(c => c.CreateTime), "RedRecord" + query.merchant_id);
                return list;
            }
        }
        /// <summary>
        /// 用户 马力 红钻 邀请码 数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public red_user_dto GetUser(long id) {
            var model = context.RedRecord.Where(s => s.MerchantId == id).FromCacheFirstOrDefault<RedRecord, red_user_dto>("RedRecord" + id);
            return model;
        }

        /// <summary>
        /// 获取红钻冻结记录
        /// </summary>
        /// <param name="query"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public PagedResult<app_red_frozen_record_dto> GetRedFrozenRecordPageList(PageQuery query, long userId) {
            var filter = PredicateBuilder.True<RedFrozenRecord>();
            filter = filter.And(c => c.MerchantId == userId);
            var result = context.RedFrozenRecord.FromCachePaged<RedFrozenRecord, app_red_frozen_record_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(c => c.CreateTime));
            if(result != null && result.rows != null) {
                foreach(var row in result.rows) {
                    row.link_url = t_RequestMethod.token_url + "/MyOrder/DistributionOrderDetail?order_id=" + row.order_id;
                }
            }
            return result;
        }
    }
    public class SortRedPower {
        public long TotalRedDrill { get; set; }
        public long TotalHorsePower { get; set; }
        public long MerchantId { get; set; }
    }
}
